﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FarseerPhysics.Dynamics;
using MapLibrary.DataLoading;
using FarseerPhysics.Factories;
using FarseerPhysics;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using UtilityLibrary;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Common;
using FarseerPhysics.Common.ConvexHull;
using FarseerPhysics.Dynamics.Contacts;
using FarseerPhysics.Common.PolygonManipulation;
using MapLibrary.MapLibrary.DataLoading;
using MapLibrary.Players.CollisionResponse;

namespace MapLibrary
{
    public class LevelCollisionRegion : ITransformable
    {
        /// <summary>
        /// Handles the creation of LevelCollisionRegions by setting up all of the necessary
        /// physics.
        /// </summary>
        /// <param name="world"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public static LevelCollisionRegion CreateLevelCollisionRegion(World world, LevelCollisionData data)
        {
            LevelCollisionRegion toReturn = new LevelCollisionRegion();

            data.Hull = GiftWrap.GetConvexHull(data.Hull);

            Vector2 centroid = data.Hull.GetCentroid();
            data.Hull.Translate(-centroid);

            //create body
            Path tPath = new Path(ConvertUnits.ToSimUnits(data.Hull));
            tPath.Closed = true;
            toReturn.Body = BodyFactory.CreateBody(world, centroid);
            PathManager.ConvertPathToPolygon(tPath, toReturn.Body, 10.0f, data.Hull.Count);

            toReturn.Position = centroid;
            toReturn.Body.BodyType = BodyType.Static;
            toReturn.Body.IsStatic = true;
            toReturn.Body.Friction = .3f;
            toReturn.Body.Restitution = 0.0f;
            toReturn.Body.CollidesWith = Category.All;
            toReturn.Body.CollisionCategories = Category.All;
            toReturn.Body.OnCollision += toReturn.OnCollision;

            toReturn.Body.UserData = toReturn;
            toReturn.Type = data.Type;

            if (toReturn.Type == "Floor")
            {
                toReturn.CollisionCategory = CollisionResponseManager.CollisionCategory.Floor;
            }
            else
                toReturn.CollisionCategory = CollisionResponseManager.CollisionCategory.None;

            return toReturn;
        }

        /// <summary>
        /// Position of the collision region.
        /// </summary>
        public Vector2 Position
        {
            get { return ConvertUnits.ToDisplayUnits(Body.Position); }
            set { Body.Position = ConvertUnits.ToSimUnits(value); }
        }


        /// <summary>
        /// Rotation of the collision region.
        /// </summary>
        public float Rotation
        {
            get { return Body.Rotation; }
            set { Body.Rotation = value; }
        }

        public string Type { get; set; }

        /// <summary>
        /// Underlying physics Body of the collision region.
        /// </summary>
        public Body Body { get; set; }

        public bool OnCollision(Fixture f1, Fixture f2, Contact contact)
        {
            if (this.Type.Equals("Mucus"))
                return false;

            return true;
        }

        public CollisionResponseManager.CollisionCategory CollisionCategory
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the CollisionData representing this LevelCollisionRegion.  It is an
        /// information only, non-dynamic, representation.  Used for saving/loading.
        /// </summary>
        /// <returns></returns>
        public LevelCollisionData GetCollisionData()
        {
            Vertices verts = new Vertices();

            foreach (Fixture f in Body.FixtureList)
            {
                PolygonShape s = (PolygonShape)f.Shape;

                foreach (Vector2 v in s.Vertices)
                {
                    verts.Add(Position + ConvertUnits.ToDisplayUnits(v));
                }
            }

            LevelCollisionData toReturn = new LevelCollisionData();
            toReturn.Hull = verts;
            toReturn.Type = this.Type;

            return toReturn;
        }

        /// <summary>
        /// Draw the collision region to the Screen.
        /// </summary>
        /// <param name="batch"></param>
        /// <param name="viewport"></param>
        public void Draw(SpriteBatch batch, WorldViewport viewport)
        {
            foreach (Fixture f in Body.FixtureList)
            {
                PolygonShape s = (PolygonShape)f.Shape;
                PrimitiveBrush.RenderHull(batch, viewport.WorldToViewportCoords(PointMath.GetTranslation(
                    ConvertUnits.ToDisplayUnits(s.Vertices), Position)));
            }
        }

        // Implementation of the ITransformable interface.
        // = = = = = =
        //

        public void SetPosition(Vector2 pos)
        {
            this.Body.Position = ConvertUnits.ToSimUnits(pos);
        }

        public Vector2 GetPosition()
        {
            return ConvertUnits.ToDisplayUnits(this.Body.Position);
        }

        public void SetRotation(float rotation)
        {
            this.Body.Rotation = rotation;
        }

        public float GetRotation()
        {
            return this.Body.Rotation;
        }

        public void SetScale(Vector2 newScale)
        {
            return;
        }

        public Vector2 GetScale()
        {
            return Vector2.Zero;
        }

        public Vector2 GetCenter()
        {
            return Vector2.Zero;
        }

        public bool IsActive()
        {
            return true;
        }
    }
}
